﻿using System;
using System.Threading;

namespace UnitDriven
{
    public sealed class UnitTestContext : IDisposable
    {
        ManualResetEvent _wait = new ManualResetEvent(false);
        Exception _error;
        AsyncAsserter _asserter;
        TimeSpan timeout;

        public UnitTestContext()
        {
            _asserter = new AsyncAsserter();
            _asserter.Complete += asserter_Complete;
            this.timeout = TimeSpan.FromSeconds(30.0);
            _wait.Reset();
        }

        public AsyncAsserter Assert
        {
            get { return _asserter; }
        }

        public void SetTimeout(TimeSpan timeout)
        {
            this.timeout = timeout;
        }

        private void asserter_Complete(object sender, AsyncAssertCompleteEventArgs e)
        {
            lock (Assert)
            {
                Assert.Complete -= asserter_Complete;
                _error = e.Error;
            }
            _wait.Set();
        }

        public void Complete()
        {
            if(!_wait.WaitOne(this.timeout))
            {
                throw new TestException("Test timed out.");
            }

            lock (Assert)
            {
                if (_error != null)
                    throw _error;
            }
        }

        public void Dispose()
        {
            using(_wait)
              Complete();

            GC.SuppressFinalize(this);
        }
    }
}
